﻿using System.Runtime.CompilerServices;

namespace zijian666.Data;

/// <summary>
/// 自动关闭的 <see cref="IDataReader"/> 结构
/// </summary>
internal readonly struct DataReaderScope : IDisposable, IAsyncDisposable
{
    private readonly IDataReader _reader;
    private readonly IDbCommand _command;
    private readonly DbExecuteReaderInterceptorContext? _context;

    public static async Task<DataReaderScope> Create(IDataReader reader, IDbCommand command, long timestamp, CancellationToken cancellationToken)
    {
        var context = await DbInterceptors.OnQueryStarting(() => new(command, reader, timestamp, cancellationToken));
        return new(reader, command, context);
    }


    private DataReaderScope(IDataReader reader, IDbCommand command, DbExecuteReaderInterceptorContext? context)
    {
        _reader = reader ?? throw new ArgumentNullException(nameof(reader));
        _command = command ?? throw new ArgumentNullException(nameof(command));
        _context = context;
    }

    public DbExecuteReaderInterceptorContext? Context => _context;

    public void SetResult(object? result)
    {
        var context = _context;
        if (context is not null)
        {
            context.Result = result;
        }
    }
    public void Dispose()
    {
        if (_reader.IsClosed)
        {
            return;
        }
        if (_reader.Read() || _reader.NextResult())
        {
            // 如果datareader未读完直接dispose,将会自动读取剩下的数据后才释放
            _command.Cancel();
        }
        var context = _context;
        if (context is not null)
        {
            _ = DbInterceptors.OnQueryExecuted(() => context).GetAwaiter().GetResult();
        }
        _reader.Close();
        _reader.Dispose();
        _command.Dispose();
    }

    public async ValueTask DisposeAsync()
    {
        if (_reader.IsClosed)
        {
            return;
        }
        var context = _context;
        var reader = _reader as DbDataReader;
        if (reader is null)
        {
            if (_reader.Read() || _reader.NextResult())
            {
                // 如果datareader未读完直接dispose,将会自动读取剩下的数据后才释放
                _command.Cancel();
            }
            if (context is not null)
            {
                await DbInterceptors.OnQueryExecuted(() => context);
            }
            _reader.Close();
            _reader.Dispose();
            _command.Dispose();
            return;
        }
        if (await reader.ReadAsync() || await reader.NextResultAsync())
        {
            // 如果datareader未读完直接dispose,将会自动读取剩下的数据后才释放
            _command.Cancel();
        }
        if (context is not null)
        {
            await DbInterceptors.OnQueryExecuted(() => context);
        }
        await reader.CloseAsync();
        await reader.DisposeAsync();
        await ((DbCommand)_command).DisposeAsync();
    }

}
